home *** CD-ROM | disk | FTP | other *** search
/ Space & Astronomy / Space and Astronomy (October 1993).iso / mac / programs / satrack / SS4EXE.ZIP / SEESAT4.ZIP / UTIL.C < prev   
Text File  |  1992-01-05  |  9KB  |  370 lines

  1. /*
  2. UTIL.C
  3. Paul S. Hirose, 1991 Dec 31
  4. User interface support functions for SEESAT satellite tracking program.
  5.  
  6. This file is in the public domain.
  7.  
  8. 100 - 199
  9.  
  10. Library functions and #defines used in this file:
  11.  
  12. atof, atoi, isalpha, NULL, printf, strcmp, strcpy, strlen, toupper
  13. */
  14.  
  15. #include "b:seesat.h"    /* global header */
  16.  
  17. #if ECOC
  18. extern void printf();
  19. extern char *strcpy();
  20. extern double atof();
  21. #endif
  22.  
  23.  
  24. /* Use 0 for normal operation.  Non-zero will make static functions & data
  25. externally visible for testing */
  26. #define NSTAT 0
  27.  
  28. #if NSTAT        /* test mode */
  29. #define STATIC        /* precedes static definitions of functions & data */
  30. #define SC extern    /* precedes declarations of static functions */
  31.  
  32. #else            /* normal mode */
  33. #define STATIC static
  34. #define SC static
  35. #endif
  36.  
  37. /*############################## DATA ##############################*/
  38.  
  39. struct month {
  40.     char *mname;    /* month name */
  41.     int difm;    /* days in full months */
  42. };
  43.  
  44. /* calendar */
  45. STATIC struct month calndr[] = {
  46.     {"JAN",   0}, {"FEB",  31}, {"MAR",  59},
  47.     {"APR",  90}, {"MAY", 120}, {"JUN", 151},
  48.     {"JUL", 181}, {"AUG", 212}, {"SEP", 243},
  49.     {"OCT", 273}, {"NOV", 304}, {"DEC", 334}, {NULL, 365}
  50. };
  51.  
  52. /*################ FUNCTIONS LOCAL TO THIS FILE ################*/
  53.  
  54. SC void cpy0p();    /* strncpy() with leading 0 padding */
  55. SC int leapyr();    /* returns 1 if arg is leap year */
  56.  
  57. /*############################## CODE ##############################*/
  58.  
  59. double
  60. atomin(string)
  61. char *string;
  62. /* Returns value (in minutes) of string of form "hhmm:ss.s...".  Leading
  63. minus sign permitted. */
  64. {
  65.     double time;
  66.     char *ptr, c, buf[5];
  67.     int sign;
  68.  
  69.     if (*string == '-') {
  70.         sign = -1;
  71.         ++string;
  72.     } else
  73.         sign = 1;
  74.     ptr = string;
  75.  
  76.     /* point to the colon (or terminating null if no colon) */
  77.     while ((c = *ptr)  &&  c != ':')
  78.         ++ptr;
  79.  
  80.     /* process seconds */
  81.     if (c) {        /* string had a colon */
  82.         time = atof(ptr + 1) / 60.;
  83.         *ptr = '\0';        /* turn ':' to '\0' */
  84.     } else
  85.         time = 0.;
  86.  
  87.     cpy0p(buf, string, 5);        /* buf[] = "hhmm" */
  88.  
  89.     time += atof(buf + 2);        /* add minutes */
  90.     buf[2] = '\0';
  91.     /* add hours, restore sign */
  92.     return (time + atof(buf) * 60.) * sign;
  93. }
  94.  
  95.  
  96. STATIC void
  97. cpy0p(dest, src, n)
  98. char *dest, *src;
  99. int n;
  100. /* Copy n-1 chars from src[] to dest[].  If src[] is too short, pad dest[]
  101. with leading '0's.  If src[] is too long, not all of src[] will be copied. 
  102. dest[] will always receive n-1 chars followed by null terminator. */
  103. {
  104.     int i, len;
  105.  
  106.     len = strlen(src);
  107.     for (i = n; --i; )
  108.         *dest++ = (i > len) ? '0' : *src++;
  109.     *dest = '\0';
  110. }
  111.  
  112.  
  113. char **
  114. degdms(pre, x)
  115. int pre;        /* precision */
  116. double x;
  117. /* Converts x degrees to 3 strings holding degrees, minutes, seconds.  "pre"
  118. specifies rounding and may be 0 - 4:  0 = nearest deg, 1 = nearest 10 min, 2
  119. = 1 min, 3 = 10 sec, 4 = 1 sec.  Domain of x (after rounding):  -1000 < x <
  120. 10000.  Returns pointer to dms[].  If pre was 1 or 2, s[] is garbage.  Both
  121. s[] & m[] are garbage if pre was 0. */
  122. {
  123.     long int lx;
  124.     int sign;
  125.     static int mult[] = {1, 6, 60, 360, 3600};
  126.     static char
  127.         d[5], m[3], sec[3],
  128.         *dms[] = {d, m, sec};
  129.  
  130.     if (x >= 0.)
  131.         sign = 1;
  132.     else {
  133.         sign = -1;
  134.         x = -x;
  135.     }
  136.  
  137.     lx = (long) (x * mult[pre] + .5) * (((unsigned) pre & 1) ? 10 : 1);
  138.     switch (pre) {
  139.     case 4:
  140.     case 3:
  141.         ITOA(sec, (int) (lx % 60));    /* seconds */
  142.         lx /= 60;
  143.     case 2:
  144.     case 1:
  145.         ITOA(m, (int) (lx % 60));    /* minutes */
  146.         lx /= 60;
  147.     }
  148.     ITOA(d, (int) lx * sign);    /* degrees */
  149.     return dms;
  150. }
  151.  
  152.  
  153. char *
  154. jdstr(jd)
  155. long int jd;    /* Julian Date, unit = days */
  156. /* Converts jd to Gregorian calendar date.  Good for both BC & AD for
  157. practically any date one might want.  More precisely, domain of jd is limited
  158. by largest/smallest year an int can hold, as well as size of buffer[]. 
  159. Returns pointer to year/month/day string, e.g., "1990 JAN 14". */
  160. {
  161.     static char buffer[13];        /* space for -yyyy mmm dd */
  162.     struct month *calp;        /* pointer into calendar */
  163.     int d, m, n;
  164.     int leap;        /* flag; 1 = leap yr */
  165.     char *cp;
  166.  
  167.     /* 1721425 = Julian Date @ 1 BC Dec 31 (Gregorian calendar), 12h UT. 
  168.     365.2425 = days per year (over the 400 yr Gregorian cycle). */
  169.     n = (jd - 1721425) / 365.2425;
  170.     if (n >= 0)
  171.         ++n;
  172.  
  173.     /*  n = estimated year.  Correct the estimate to actual year.  The
  174.     preceding formula can mistakenly yield an AD year from a BC jd, but
  175.     the reverse will never happen.  Therefore, we need only guard against
  176.     n being DECREMENTED to 0 (which is an undefined year). */
  177.  
  178.     while (1) {
  179.         d = jd - julday(n, 0, 0);
  180.         leap = leapyr(n);    /* true if leap year */
  181.         if (d <= 365 + leap  &&  d >= 1)
  182.             break;
  183.         if (d < 1) {
  184.             --n;
  185.             if (n == 0)
  186.                 --n;    /* skip year 0 */
  187.         } else
  188.             ++n;
  189.     }
  190.     ITOA(buffer, n);    /* write the year */
  191.     cp = buffer + strlen(buffer);
  192.     *cp++ = ' ';
  193.  
  194.     /* Determine month.  Begin by moving forward thru the calendar a
  195.     month at a time (starting with Feb) till we overshoot */
  196.  
  197.     calp = calndr;        /* point to Jan */
  198.     m = 0;            /* month counter; 0 = Jan */
  199.     do {
  200.         ++calp;        /* point to next month in calendar */
  201.         ++m;        /* month counter */
  202.         n = calp->difm;
  203.         if (m >= 2 && leap)    /* March or later, & leap yr */
  204.             ++n;
  205.     } while (d > n);
  206.  
  207.     /* We've overshot by one month.  Decrement calendar pointer "calp". 
  208.     Month counter "m" has overshot too, so the "m >= 3" test actually
  209.     means "March or later".  After subtracting days in full months, d =
  210.     day of month. */
  211.     d -= (--calp)->difm + (m >= 3 && leap);
  212.  
  213.     /* write month & day */
  214.     strcpy(cp, calp->mname);
  215.     cp += 3;
  216.     *cp++ = ' ';
  217.     ITOA(cp, d);
  218.     return buffer;
  219. }
  220.  
  221.  
  222. long int
  223. julday(y, m, d)
  224. int y, m, d;        /* year, month (Jan = 0), day */
  225. /* Returns Julian Date (unit = days) corresponding to 12h UT on given date,
  226. Gregorian calendar.  Jan = month 0.  Use -1 for 1 BC, etc.  Any integer
  227. is legal for d. */
  228. {
  229.     int bc;        /* flag; 1 = BC */
  230.  
  231.     if (m > 1)    /* after Feb */
  232.         d += leapyr(y);        /* add 1 if leap yr */
  233.  
  234.     if (y >= 0) {
  235.         --y;
  236.         bc = 0;
  237.     } else {
  238.         y = -(y + 1);
  239.         bc = 1;
  240.     }
  241.     return ((bc ? 366 : 0) + y*365L + y/4 - y/100 + y/400) *
  242.       (bc ? -1 : 1) + calndr[m].difm + d + 1721425;
  243.     /* 1721425 = Julian Date for 1 BC Dec 31 12h, Gregorian calendar */
  244. }
  245.  
  246.  
  247. STATIC int
  248. leapyr(y)
  249. int y;
  250. /* Returns 1 if y is leap year in Gregorian calendar, 0 otherwise.  To
  251. signify BC year use a negative number, e.g., -1 for 1 BC. */
  252. {
  253.     /* For leap year determination purposes, 1 BC = 0, 2 BC = -1, etc. 
  254.     Therefore, we must make an adjustment to y if it's BC. */
  255.     if (y < 0)
  256.         ++y;
  257.     return !(y%4) && y%100  ||  !(y%400);
  258. }
  259.  
  260.  
  261. char *
  262. stoup(string)
  263. char *string;
  264. /* Converts "string" to all upper case, returns "string". */
  265. {
  266.     char *cp;
  267.     int i;
  268.  
  269.     for (cp = string; i = *cp; ++cp)
  270.         if (isalpha(i))
  271.             *cp = toupper(i);
  272.     return string;
  273. }
  274.  
  275.  
  276. char *
  277. timstr(m)
  278. double m;    /* minutes */
  279. /* Turns m into a string of format "hhmm:ss" (or "-hhmm:ss" if m is
  280. negative), rounded to nearest second.  Be sure that hours will not require
  281. more than two digits.  String will be padded with zeros to fill out all six
  282. digits.  Returns the string. */
  283. {
  284.     static char buf[9];
  285.     char *cp, **cpp;
  286.     int minus;        /* flag; 1 = negative */
  287.  
  288.     cp = buf;
  289.     cpp = degdms(4, m / 60.);
  290.  
  291.     if (m < 0.) {
  292.         *cp++ = '-';
  293.         minus = 1;
  294.     } else
  295.         minus = 0;
  296.     cpy0p(cp, cpp[0] + minus, 3);
  297.     cpy0p(cp + 2, cpp[1], 3);
  298.     cp[4] = ':';
  299.     cpy0p(cp + 5, cpp[2], 3);
  300.  
  301.     return buf;
  302. }
  303.  
  304.  
  305. void
  306. tokjum(t)
  307. struct jdtim *t;
  308. /* Converts command line arguments (pointed to by global "tokp") into Julian
  309. Date & minutes.  NO conversion to UTC occurs!  tokp[0] thru [3] = {year,
  310. month, day, time}.  Month must be first 3 letters of name.  Year, month, or
  311. day may be omitted if the arguments to its left are also omitted.  On exit,
  312. tokp will point to the time argument.  Returns JD & minutes in struct "t". */
  313. {
  314.     static int date[3];    /* default year, month (Jan = 0), day */
  315.  
  316.     struct month *calp;    /* pointer into calendar */
  317.     int m, n;
  318.     char *cp, **cpp;
  319.  
  320.     /* Set n to # of date arguments.  Can be 0 - 3. */
  321.  
  322.     /* point cpp to next arg beginning with a letter, or end of cmd line,
  323.     whichever comes first */
  324.     for (cpp = tokp; (cp = *cpp) && !isalpha(*cp); ++cpp)
  325.         ;
  326.  
  327.     if (cp == NULL)        /* reached end of command line */
  328.         n = cpp - tokp - 1;
  329.     else {            /* is cp[] a month name? */
  330.         for (calp = calndr + 11, m = 11; m >= 0 &&
  331.           strcmp(cp, calp->mname); --calp, --m)
  332.             ;    /* look for cp[] in calendar */
  333.         /* if m >= 0 it's a month name, otherwise it's next cmd */
  334.         n = cpp - tokp + ((m >= 0) ? 2 : -1);
  335.     } if (n > 3  ||  n < 0) {
  336.         printf("BAD %s DATE\n", *(tokp - 1));
  337.         LONGJMP(reset, 1);
  338.     }
  339.     /* if year, month, or day were given, set them as new defaults */
  340.     switch (n) {
  341.     case 3:
  342.         date[0] = atoi(*tokp++);    /* year */
  343.     case 2:
  344.         date[1] = m;            /* month */
  345.         ++tokp;
  346.     case 1:
  347.         date[2] = atoi(*tokp++);    /* day */
  348.     }
  349.     if (date[0] == 0) {    /* year = 0, i.e., full date not given yet */
  350.         printf("DATE HAS NOT BEEN SET\n");
  351.         LONGJMP(reset, 1);
  352.     }
  353.     /* compute Julian Date & time of day */
  354.     t->jd = julday(date[0], date[1], date[2]);
  355.     t->time = atomin(*tokp);
  356. }
  357.  
  358.  
  359. double
  360. tokmin()
  361. /* Same as tokjum() except returns epoch expressed as minutes instead of
  362. Julian Date & minutes, and the time zone is Greenwich. */
  363. {
  364.     struct jdtim t;
  365.  
  366.     tokjum(&t);
  367.     return t.jd * xmnpda - 720. + t.time - tzone;
  368. }
  369. = 11; m >= 0 &&
  370.           strcmp(cp, cal